package com.wxzz.elearing.user.service.impl;

import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.wxzz.elearing.user.amqp.producer.UserMessageProducer;
import com.wxzz.elearing.user.dto.*;
import com.wxzz.elearing.user.entity.*;
import com.wxzz.elearing.user.mapper.*;
import com.wxzz.elearing.user.service.IAdminUserService;
import com.wxzz.elearning.common.bean.SmsConfig;
import com.wxzz.elearning.common.constants.RedisConstants;
import com.wxzz.elearning.common.dto.SystemMessageMqDto;
import com.wxzz.elearning.common.exception.ServiceException;
import com.wxzz.elearning.common.utils.ExcelUtils;
import com.wxzz.elearning.common.utils.IPUtils;
import com.wxzz.elearning.common.utils.MD5Util;
import com.wxzz.elearning.common.utils.SmsUtil;
import com.wxzz.elearning.common.vo.JgPageVo;
import com.wxzz.elearning.common.vo.ReturnVO;
import lombok.SneakyThrows;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.connection.RedisConnection;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.time.LocalDate;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
import java.util.UUID;
import java.util.concurrent.TimeUnit;

/**
 * <p>
 * 系统用户 服务实现类
 * </p>
 *
 * @author
 * @since 2021-03-11
 */
@Service
public class AdminUserServiceImpl extends ServiceImpl<AdminUserMapper, AdminUser> implements IAdminUserService {

    @Autowired
    private RedisTemplate<String, String> redisTemplate;

    @Autowired
    private AdminUserMapper adminUserMapper;

    @Autowired
    private DocentMapper docentMapper;

    @Autowired
    private EnterpriseMapper enterpriseMapper;

    @Override
    public ReturnVO<AdminUser> adminUserLogin(AdminLoginDto adminLoginDto) {
        if (adminLoginDto.getUsername() == null) {
            throw new ServiceException("账号不能为空");
        }
        if (StringUtils.isBlank(adminLoginDto.getPassword())) {
            throw new ServiceException("密码不能为空");
        }
        adminLoginDto.setPassword(MD5Util.md5Encrypt32Upper(adminLoginDto.getPassword()));
        Optional<AdminUser> adminUserOptional = adminUserMapper.selectAdminUser(adminLoginDto);
        //2分钟内限制登录次数
        if (!adminUserOptional.isPresent()) {
            Integer loginNum = 0;
            String s = redisTemplate.opsForValue().get(RedisConstants.LOGIN_NUM + adminLoginDto.getUsername());
            if (StringUtils.isNotBlank(s) && Integer.valueOf(s) > 2) {
                throw new ServiceException("频繁操作,请" + redisTemplate.opsForValue().getOperations().getExpire(RedisConstants.LOGIN_NUM + adminLoginDto.getUsername()) + "秒后再试");
            } else {
                if (StringUtils.isNotBlank(s)){
                    loginNum = Integer.valueOf(s);
                }else {
                    loginNum = 1;
                }
            }
            redisTemplate.opsForValue().set(RedisConstants.LOGIN_NUM + adminLoginDto.getUsername(), String.valueOf(loginNum + 1), 2 * 60, TimeUnit.SECONDS);
        }
        adminUserOptional.orElseThrow(() -> new ServiceException("账号或密码错误"));
        AdminUser adminUser = adminUserOptional.get();
        if (adminUser.getStatus() == 0) {
            throw new ServiceException("该账号已禁用");
        }
        Enterprise enterprise = enterpriseMapper.selectById(adminUser.getEnterpriseId());
        if (enterprise != null && enterprise.getIsBan() == 1) {
            throw new ServiceException("该企业已经被禁用");
        }
        //讲师端判断
//        if (adminLoginDto.getType() == 2) {
//            Docent docent = docentMapper.selectById(adminUser.getDocentId());
//            if (docent == null) {
//                new ServiceException("该讲师账号不存在");
//            }
//            if (docent.getDocentStatus() == 2) {
//                throw new ServiceException("该讲师账号已被封号");
//            }
//        }
        //三端账号判断
        String token = RedisConstants.ADMIN_TOKEN + UUID.randomUUID().toString();
//        //总后台
//        if (adminLoginDto.getType() == 0) {
//            if (adminUser.getType() != 0) {
//                throw new ServiceException("该账号非总后台账号");
//            }
//            token = RedisConstants.ADMIN_TOKEN + UUID.randomUUID().toString();
//        }
//        //企业后台
//        if (adminLoginDto.getType() == 1) {
//            if (adminUser.getType() != 0) {
//                throw new ServiceException("该账号非企业后台账号");
//            }
//            token = RedisConstants.ENTERPRISE_TOKEN + UUID.randomUUID().toString();
//        }
//        //讲师端
//        if (adminLoginDto.getType() == 2) {
//            if (adminUser.getIsDocent() != 1) {
//                throw new ServiceException("该账号非讲师端账号");
//            }
//            token = RedisConstants.DOCENT_TOKEN + UUID.randomUUID().toString();
//        }
//        if (StringUtils.isNotBlank(adminUser.getAdminToken())) {
//            if (redisTemplate.hasKey(adminUser.getAdminToken())) {
//                //删除废弃token
//                redisTemplate.delete(adminUser.getAdminToken());
//            }
//        }
        //更新token
        adminUser.setAdminToken(token);
        adminUserMapper.updateById(adminUser);
        redisTemplate.opsForValue().set(token, JSONObject.toJSONString(adminUser), 60 * 60 * 24 * 10 * 30, TimeUnit.SECONDS);
        //登录日志
        LoginLog loginLog = new LoginLog();
        AdminRole adminRole = adminRoleMapper.selectAdminRoleByAdminUserId(adminUser.getId());
        if (adminRole != null) {
            loginLog.setAdminRoleName(adminRole.getRoleName());
        }
        loginLog.setEnterpriseId(adminUser.getEnterpriseId());
        loginLog.setImage(adminUser.getImage());
        loginLog.setPhone(adminUser.getPhone());
        loginLog.setUsername(adminUser.getUsername());
        loginLog.setName(adminUser.getName());
        HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
        loginLog.setIp(IPUtils.getIpAddr(request));
        loginLogMapper.insert(loginLog);
        return new ReturnVO<>("登录成功", adminUser);
    }

    @Autowired
    private LoginLogMapper loginLogMapper;

    @Override
    public ReturnVO saveAdminUser(Long enterpriseId, AdminUserInsDto adminUserInsDto) {
        AdminUser exist = adminUserMapper.selectOne(new LambdaQueryWrapper<AdminUser>().eq(AdminUser::getUsername, adminUserInsDto.getUsername()));
        if (exist != null && !exist.getId().equals(adminUserInsDto.getId())) {
            throw new ServiceException("该后台账号已被使用");
        }
        AdminUser adminUser = new AdminUser();
        if (adminUserInsDto.getId() == null) {
            if (StringUtils.isBlank(adminUserInsDto.getUsername()) || StringUtils.isBlank(adminUserInsDto.getPassword())) {
                throw new ServiceException("账号或密码不能为空");
            }

            BeanUtils.copyProperties(adminUserInsDto, adminUser);
            adminUser.setPassword(MD5Util.md5Encrypt32Upper(adminUserInsDto.getPassword()));
            adminUser.setEnterpriseId(enterpriseId);
            adminUserMapper.insert(adminUser);
        } else {
            BeanUtils.copyProperties(adminUserInsDto, adminUser);
            if (StringUtils.isNotBlank(adminUserInsDto.getPassword())) {
                adminUser.setPassword(MD5Util.md5Encrypt32Upper(adminUserInsDto.getPassword()));
            }
            adminUser.setEnterpriseId(enterpriseId);
            adminUserMapper.updateById(adminUser);
        }
        AdminUser result = adminUserMapper.selectById(adminUser.getId());
        return new ReturnVO("账号创建成功", result);
    }

    @Override
    public ReturnVO<JgPageVo<LoginLog>> listLoginLog(Long enterpriseId, LoginLogDto loginLogDto) {
        PageHelper.startPage(loginLogDto.getCurPage(), loginLogDto.getMaxPage());
        QueryWrapper<LoginLog> queryWrapper = new QueryWrapper<>();
        queryWrapper.orderByDesc("create_time");
        queryWrapper.eq("enterprise_id", enterpriseId);
        if (StringUtils.isNotBlank(loginLogDto.getIp())) {
            queryWrapper.like("ip", loginLogDto.getIp() + "%");
        }
        if (StringUtils.isNotBlank(loginLogDto.getUsername())) {
            queryWrapper.like("username", loginLogDto.getUsername() + "%");
        }
        if (StringUtils.isNotBlank(loginLogDto.getPhone())) {
            queryWrapper.like("phone", loginLogDto.getPhone() + "%");
        }
        List<LoginLog> loginLogs = loginLogMapper.selectList(queryWrapper);
        return new ReturnVO("登录日志查询", new JgPageVo<>(new PageInfo(loginLogs)));
    }

    @Autowired
    private AdminRoleMapper adminRoleMapper;

    @SneakyThrows
    @Override
    public ReturnVO<JgPageVo<List<AdminUser>>> listAdminUser(HttpServletResponse response, Long enterpriseId, AdminUserDto adminUserDto) {
        PageHelper.startPage(adminUserDto.getCurPage(), adminUserDto.getMaxPage());
        QueryWrapper queryWrapper = new QueryWrapper();
        queryWrapper.eq("enterprise_id", enterpriseId);
        //不展示讲师端账号
        queryWrapper.eq("is_docent", 0);
        queryWrapper.orderByDesc("create_time");
        if (adminUserDto.getIsApproval() != null) {
            queryWrapper.eq("is_approval", adminUserDto.getIsApproval());
        }
        if (adminUserDto.getIsDocent() != null) {
            queryWrapper.eq("is_docent", adminUserDto.getIsDocent());
        }
        if (adminUserDto.getStatus() != null) {
            queryWrapper.eq("status", adminUserDto.getStatus());
        }
        if (StringUtils.isNotBlank(adminUserDto.getPhone())) {
            queryWrapper.like("phone", adminUserDto.getPhone() + "%");
        }
        if (StringUtils.isNotBlank(adminUserDto.getUsername())) {
            queryWrapper.like("username", adminUserDto.getUsername() + "%");
        }
        if (StringUtils.isNotBlank(adminUserDto.getName())) {
            queryWrapper.like("name", adminUserDto.getName() + "%");
        }
        if (StringUtils.isNotBlank(adminUserDto.getRemark())) {
            queryWrapper.eq("remark", adminUserDto.getRemark() + "%");
        }
        List<AdminUser> adminUserList = adminUserMapper.selectList(queryWrapper);
        //查询用户对应的角色信息
        adminUserList.forEach(adminUser -> {
            AdminRole adminRole = adminRoleMapper.selectAdminRoleByAdminUserId(adminUser.getId());
            if (adminRole != null) {
                adminUser.setRoleName(adminRole.getRoleName());
                adminUser.setAdminRole(adminRole);
            }
        });
        if (adminUserDto.getIsExport() != null && adminUserDto.getIsExport() == 1) {
            ExcelUtils.exportExcel(adminUserList, "后台账号列表", "后台账号列表", AdminUser.class, "后台账号列表", response);
            return new ReturnVO("后台账号列表导出成功", null);
        }
        return new ReturnVO("账号列表查询成功", new JgPageVo(new PageInfo<>(adminUserList)));
    }

    @Override
    public ReturnVO sendCode(SendCodeDto sendCodeDto) {
        if (StringUtils.isBlank(sendCodeDto.getPhone())) {
            throw new ServiceException("请传入手机号");
        }
        AdminUser adminUser = adminUserMapper.selectOne(new LambdaQueryWrapper<AdminUser>()
                .eq(AdminUser::getUsername, sendCodeDto.getUsername()));
        Optional.ofNullable(adminUser).orElseThrow(() -> new ServiceException("该账号不存在"));
        if (!sendCodeDto.getPhone().equals(adminUser.getPhone())) {
            throw new ServiceException("该手机号不对应该账号");
        }
        //发送验证码
        int intFlag = (int) (Math.random() * 1000000);
        String flag = String.valueOf(intFlag);
        if (flag.length() == 6 && flag.substring(0, 1).equals("9")) {
        } else {
            intFlag = intFlag + 100000;
        }
        redisTemplate.opsForValue().set(RedisConstants.PHONE_CODE + sendCodeDto.getUsername(), String.valueOf(intFlag));
        SystemMessageMqDto systemMessageMqDto = new SystemMessageMqDto();
        //验证码类短信
        systemMessageMqDto.setSmsType(1);
        systemMessageMqDto.setPhones(
                new ArrayList<String>() {
                    {
                        add(sendCodeDto.getPhone());
                    }
                }
        );
        systemMessageMqDto.setTemplateId(SmsConfig.findPasswordId);
        int finalIntFlag = intFlag;//匿名内部类语法规则
        systemMessageMqDto.setParams(new ArrayList<String>() {
            {
                add(String.valueOf(finalIntFlag));
            }
        });
        userMessageProducer.ackMQSender(JSONObject.toJSONString(systemMessageMqDto));
        return new ReturnVO("验证码发送成功", null);
    }

    @Override
    public ReturnVO updatePassword(UpdatePasswordDto updatePasswordDto) {
        AdminUser adminUser = adminUserMapper.selectOne(new LambdaQueryWrapper<AdminUser>()
                .eq(AdminUser::getUsername, updatePasswordDto.getUsername()));
        Optional.ofNullable(adminUser).orElseThrow(() -> new ServiceException("该账号不存在"));
        if (StringUtils.isBlank(updatePasswordDto.getCode())) {
            throw new ServiceException("请输入验证码");
        }
        String code = redisTemplate.opsForValue().get(RedisConstants.PHONE_CODE + updatePasswordDto.getUsername());
        if (!updatePasswordDto.getCode().equals(code)) {
            throw new ServiceException("验证码错误");
        }
        adminUser.setPassword(MD5Util.md5Encrypt32Upper(updatePasswordDto.getPassword()));
        adminUserMapper.updateById(adminUser);
        return new ReturnVO("密码修改成功", adminUser.getId());
    }

    @Override
    public ReturnVO deleteByAdminUserId(Long adminUserId) {
        AdminUser adminUser = adminUserMapper.selectById(adminUserId);
        Optional.ofNullable(adminUser).orElseThrow(() -> new ServiceException("该账号不存在"));
        if (adminUser.getIsAdmin() == 1) {
            throw new ServiceException("admin账号无法删除");
        }
        adminUserMapper.deleteById(adminUserId);
        return new ReturnVO("账号删除", adminUserId);
    }

    @Autowired
    private UserMessageProducer userMessageProducer;

}
